module Main where

import qualified ApxBB
import qualified BsBB
import qualified BB
import Interlude
import System.Environment (getArgs, getProgName)
import System.Console.GetOpt (OptDescr(..), ArgDescr(..), ArgOrder(..), getOpt, usageInfo)
import System.Exit (exitSuccess)

appID :: String
appID = "Sergei 0.2"

data Options = Options
  { verbosity   :: Int
  , help        :: Bool
  , rationals   :: Bool
  , nonPoly     :: Bool
  , epsilon     :: Maybe Double }

defaultOpts :: Options
defaultOpts = Options 0 False False False Nothing

options :: [OptDescr (Options -> Options)]
options =
  [ Option "v"  ["verbose"]   (NoArg $ \o -> o { verbosity = verbosity o + 1})  "verbose output"
  , Option "r"  ["rationals"] (NoArg $ \o -> o { rationals = True })            "use rational numbers"
  , Option "n"  ["nonpoly"]   (NoArg $ \o -> o { nonPoly = True })              "allow non-polynomial functions"
  , Option "h?" ["help"]      (NoArg $ \o -> o { help = True })                 "display help"
  , Option "e"  ["eps"]       (ReqArg (\e o -> o { epsilon = Just $ read e }) "VALUE") "required tightness of bounds" ]

main :: IO ()
main = do
  a <- getArgs
  pn <- getProgName
  let forHelp = "Type `" ++ pn ++ " -h' for help."
  let (foldl (flip id) defaultOpts -> opts, file, errs) = getOpt Permute options a
  when (help opts) $ putStrLn $ usageInfo (appID ++ "\nUsage: " ++ pn ++ " [options] [file]") options
  _ <- exitSuccess
  if errs /= [] then error $ concat errs ++ forHelp else
    let inp = case file of
          []  -> getContents
          [f] -> readFile f
          _   -> error $ "Can handle only one file at once.\n" ++ forHelp in
    let v = verbosity opts in
    let run trm box = BB.inf trm v box >> return () in
    inp >>= writeStdIO . case (nonPoly opts, rationals opts) of
      (False,False) -> BsBB.prepare v >=> run (BsBB.trm $ epsilon opts)
      (False,True)  -> BsBB.prepare v >=> run (BsBB.trm $ toRational <$> epsilon opts)
      (True ,False) -> ApxBB.prepare v >=> run (ApxBB.trm $ epsilon opts)
      (True ,True)  -> error "Cannot use rational numbers for non-polynomial functions."
